/* HTTP parser.
 * This file is part of AGet. See main.h to get more info.
 */
#ifndef _WUXI_HTTP_
#define _WUXI_HTTP_

/**
 * url encode, except: [-_.!~*'();/?:@&=+$,#]
 *
 * @param char* buf, output buffer.
 * @param size_t blen, length of buf.
 * @param const char* s, the url to be encoded.
 *
 * @return char*, returns first address of *buf.
 *
 * @note buf MUST BE different from s.
 */
char* urlencode(char* buf, size_t blen, const char* s);

/**
 * url encode, except: [_-.]
 * @see urlencode()
 */
char* urlencode_all(char* buf, size_t blen, const char* s);

/**
 * url decode
 * @see urlencode()
 */
char* urldecode(char* buf, size_t blen, const char* s);


/**
 * http options:
 */
typedef struct httpoptions {
    const char*  host;
    unsigned int port;
    const char*  path;
    FILE*        request; /**< output request */
} httpopt_t;

/**
 * http string garbage struct:
 */
struct strgarbage {
    char *str;
    struct strgarbage* next;
};

/**
 * HTTP data-queue node struct:
 */
struct hnode {
    char*         str;  /* header string */
    struct hnode* next; /* next header node */
};

/**
 * HTTP instance struct:
 */
typedef struct httpinstance {
    int              sck;     /**< opened socket */
    struct hnode*    head;    /**< head pointer of header-queue */
    struct hnode*    tail;    /**< tail pointer of header-queue */
    struct hnode*    data;    /**< data head pointer */
    struct strgarbage* garbage; /**< string garbage pointer */
} HTTP;

/**
 * open a HTTP request.
 *
 * @param int sck, opened socket.
 */
HTTP* http_open(int sck);

/**
 * close a HTTP request pointer.
 *
 * @param HTTP* http, opened HTTP pointer.
 */
void http_close(HTTP* http);

/**
 * set http request headers. 
 *
 * @param const char* str, header string end with '\0'. DO NOT add CRLF at the
 *                    end.
 * @param int replace, this function will try to replace similar header if
 *            its value is non-zero; otherwise, this function will simplely
 *            append new header at the end of header-queue.
 */
void http_header(HTTP* http, const char* str, int replace);

/**
 * set http request data.
 */
void http_data(HTTP* http, const char* name, const char* value);

/**
 * send a http request using GET method and get total response bytes length.
 *
 * @param char*  buf, buffer to store response header, if it's non-NULL.
 * @param size_t blen, length of buf.
 *
 * @return int, total response body length. Notice: returned value equal to 0
 *         most of time doesen't mean body length is 0, it means the body
 *         length field didn't appear in the HTTP response header.
 */
int http_get(HTTP* http, httpopt_t* hopt, char* buf, size_t blen);

/**
 * read data from a opened HTTP request pointer, and the HTTP pointer must
 * send request(using function http_get) before this function.
 *
 * @param char* buf, read buffer. Note, this function DO NOT add addition
 *              '\0' at the end of buffer, you should do it yourself.
 * @param size_t size, expected read byte size, the real read length may
 *               smaller than your expected size.
 *
 * @return int. Positive number indicates the real read lenght, or 0 indicates
 *         all data are read, or negative number indicates error.
 */
int http_read(HTTP* http, char* buf, size_t size);


/**
 * get first 'Set-Cookie' position in response header.
 *
 * @param const char* header, response header.
 *
 * @return char*. Returns NULL if no 'Set-Cookie' found, otherwise returns
 *         a char* indicate the beginning of 'Set_cookie' field in header.
 */
char* http_get_cookie(const char* header);


#endif
